/**
 * Copyright (c) 2020-2021 ThunderSoft
 * All Rights Reserved by Thunder Software Technology Co., Ltd and its affiliates.
 * You may not use, copy, distribute, modify, transmit in any form this file
 * except in compliance with ThunderSoft in writing by applicable law.
 *
 */

#include "wifi_device.h"

#include <securec.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <los_memory.h>

#include "wifi_device_util.h"
#include "wifi_hotspot_config.h"
#include "wifi_mgmr.h"
#include "utils_file.h"


typedef struct {
    char ssid[BL_WIFI_MAX_SSID_LEN + 1];    /**< SSID. CNcomment: SSID 只支持ASCII字符.CNend */
    bl_wifi_auth_mode auth;                 /**< Authentication mode. CNcomment: 认证类型.CNend */
    char key[BL_WIFI_MAX_KEY_LEN + 1];      /**< Secret key. CNcomment: 秘钥.CNend */
    unsigned char bssid[BL_WIFI_MAC_LEN];   /**< BSSID. CNcomment: BSSID.CNend */
} bl_wifi_assoc_request;

typedef void *wifi_interface_t;

#define WIFI_RECONN_POLICY_ENABLE        1
#define WIFI_RECONN_POLICY_TIMEOUT       60
#define WIFI_RECONN_POLICY_PERIOD        600
#define WIFI_RECONN_POLICY_MAX_TRY_COUNT 3
#define WIFI_DISCONNECT_REASON_NO_AP     1
#define WIFI_DEFAULT_KEY_FOR_PSK    "wifipskmode"
#define BL_WIFI_MAX_SSID_LEN             32
#define BL_OK                            0
#define EV_WIFI 0x0002
#define CODE_WIFI_ON_INIT_DONE 1
#define CONFIG_FILE_NAME            "ConfigFile"


static int g_wifiStaStatus = WIFI_STA_NOT_ACTIVE;
static WifiDeviceConfig g_wifiConfigs[WIFI_MAX_CONFIG_SIZE] = {
        {
            {0}, {0}, {0}, 0, WIFI_CONFIG_INVALID, 0, 0, UNKNOWN, {0}
        }
    };
static WifiEvent* g_wifiEvents[WIFI_MAX_EVENT_SIZE] = {0};
static int g_connectState = WIFI_STATE_NOT_AVALIABLE;
static wifi_interface_t g_wifiInterface;

static void cb_scan_item_parse(wifi_mgmr_ap_item_t *env, uint32_t *param1, wifi_mgmr_ap_item_t *item)
{
    uint32_t counter = (*param1);

    if (counter >= WIFI_SCAN_HOTSPOT_LIMIT) {
        return;
    }

    wifi_mgmr_ap_item_t *ap_ary_ptr = (wifi_mgmr_ap_item_t *)env + counter;
    counter++;

    ap_ary_ptr->channel = item->channel;
    ap_ary_ptr->rssi = item->rssi;
    memcpy(ap_ary_ptr->bssid, item->bssid, sizeof(ap_ary_ptr->bssid));
    memcpy(ap_ary_ptr->ssid, item->ssid, sizeof(ap_ary_ptr->ssid));
    ap_ary_ptr->ssid_len = strlen((char *)ap_ary_ptr->ssid);
    ap_ary_ptr->auth = item->auth;

    (*param1) = counter;
}

static void scan_complete_cb(void *p_arg, void *param)
{
    (void)p_arg;
    (void)param;
    printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
    LockWifiEventLock();
    for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
        if (g_wifiEvents[i] == NULL) {
            continue;
        }
        printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n");
        g_wifiEvents[i]->OnWifiScanStateChanged(WIFI_STATE_AVALIABLE, 0);
    }
    UnlockWifiEventLock();
}

static WifiErrorCode InitWifi(void) {
    static uint8_t stack_wifi_init  = 0;

    if (1 == stack_wifi_init) {
        puts("Wi-Fi Stack Started already!!!\r\n");
        return;
    }
    stack_wifi_init = 1;

    printf("Start Wi-Fi fw @%lums\r\n", bl_timer_now_us()/1000);
    hal_wifi_start_firmware_task();
    printf("Start Wi-Fi fw is Done @%lums\r\n", bl_timer_now_us()/1000);
    aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0);
}

WifiErrorCode EnableWifi(void)
{
    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    if (g_wifiStaStatus == WIFI_STA_ACTIVE) {
        if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return ERROR_WIFI_BUSY;
    }

    InitWifi();

    g_wifiInterface = wifi_mgmr_sta_enable();
    g_wifiStaStatus = WIFI_STA_ACTIVE;

    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    return WIFI_SUCCESS;
}

WifiErrorCode DisableWifi(void)
{
    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    if (g_wifiStaStatus == WIFI_STA_NOT_ACTIVE) {
        if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return ERROR_WIFI_NOT_STARTED;
    }

    wifi_mgmr_sta_disable(NULL);

    g_wifiStaStatus = WIFI_STA_NOT_ACTIVE;
    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    return WIFI_SUCCESS;
}

int IsWifiActive(void)
{
    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    int ret = g_wifiStaStatus;

    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    return ret;
}

WifiErrorCode Scan(void)
{
    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    if (g_wifiStaStatus == WIFI_STA_NOT_ACTIVE) {
        if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return ERROR_WIFI_NOT_STARTED;
    }
    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    if (LockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
        if (g_wifiEvents[i] == NULL) {
            continue;
        }
        g_wifiEvents[i]->OnWifiScanStateChanged(WIFI_STATE_NOT_AVALIABLE, 0);
    }
    if (UnlockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    wifi_mgmr_scan(NULL, scan_complete_cb);

    return WIFI_SUCCESS;
}

static bl_wifi_scan_type ScanTypeSwitch(WifiScanType type)
{
    bl_wifi_scan_type ret = BL_WIFI_BASIC_SCAN;

    switch (type) {
        case WIFI_FREQ_SCAN:
            ret = BL_WIFI_CHANNEL_SCAN;
            break;
        case WIFI_SSID_SCAN:
            ret = BL_WIFI_SSID_SCAN;
            break;
        case WIFI_BSSID_SCAN:
            ret = BL_WIFI_BSSID_SCAN;
            break;
        default:
            break;
    }

    return ret;
}

WifiErrorCode AdvanceScan(WifiScanParams *params)
{
    int hiRet;
    if (params == NULL) {
        return ERROR_WIFI_UNKNOWN;
    }

    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    if (g_wifiStaStatus == WIFI_STA_NOT_ACTIVE) {
        if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return ERROR_WIFI_NOT_STARTED;
    }

    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    if (LockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
        if (g_wifiEvents[i] == NULL) {
            continue;
        }
        g_wifiEvents[i]->OnWifiScanStateChanged(WIFI_STATE_NOT_AVALIABLE, 0);
    }
    if (UnlockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    if (WIFI_FREQ_SCAN == params->scanType) {
        if (params->freqs <= 0) {
            return ERROR_WIFI_UNKNOWN;
        }
    } else if (WIFI_SSID_SCAN == params->scanType) {
        if (params->ssidLen == 0) {
            return ERROR_WIFI_UNKNOWN;
        }
    } else if (WIFI_BSSID_SCAN == params->scanType) {
        if (params->bssid[0] == 0x00 &&
            params->bssid[1] == 0x00 &&
            params->bssid[2] == 0x00 &&
            params->bssid[3] == 0x00 &&
            params->bssid[4] == 0x00 &&
            params->bssid[5] == 0x00) {
            return ERROR_WIFI_UNKNOWN;
        }
    } else if (WIFI_BAND_SCAN == params->scanType) {
        if (params->ssidLen == 0) {
            //return WIFI_SUCCESS;
            hiRet = wifi_mgmr_scan(NULL, scan_complete_cb);
            if (hiRet != BL_OK) {
                printf("[wifi_service]:Advance Scan failed\r\n");
                return ERROR_WIFI_UNKNOWN;
            }
        }
    } else {
        return WIFI_SUCCESS;
    }

    int cpyErr;
    bl_wifi_scan_params sp = {0};

    cpyErr = memcpy_s(sp.ssid, sizeof(sp.ssid), params->ssid, params->ssidLen);
    if (cpyErr != EOK) {
        return ERROR_WIFI_UNKNOWN;
    }
    cpyErr = memcpy_s(sp.bssid, sizeof(sp.bssid), params->bssid, sizeof(params->bssid));
    if (cpyErr != EOK) {
        return ERROR_WIFI_UNKNOWN;
    }
    sp.ssid_len = params->ssidLen;
    sp.scan_type = ScanTypeSwitch(params->scanType);
    sp.channel = FrequencyToChannel(params->freqs);

    hiRet = wifi_mgmr_scan(NULL, scan_complete_cb);
    if (hiRet != BL_OK) {
        printf("[wifi_service]:Advance Scan failed\r\n");
        return ERROR_WIFI_UNKNOWN;
    }

    return WIFI_SUCCESS;
}

extern wifi_mgmr_t wifiMgmr;
WifiErrorCode GetScanInfoList(WifiScanInfo* result, unsigned int* size)
{
    if (result == NULL || size == NULL || *size == 0) {
        return ERROR_WIFI_INVALID_ARGS;
    }

    unsigned int num = WIFI_SCAN_HOTSPOT_LIMIT;
    unsigned int count = 0;
    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    wifi_mgmr_ap_item_t *pstResults = LOS_MemAlloc(m_aucSysMem0, sizeof(wifi_mgmr_ap_item_t) * WIFI_SCAN_HOTSPOT_LIMIT);

    for (unsigned int i = 0; i < sizeof(wifiMgmr.scan_items)/sizeof(wifiMgmr.scan_items[0]); i++) {
        if (wifiMgmr.scan_items[i].is_used && (!wifi_mgmr_scan_item_is_timeout(&wifiMgmr, &wifiMgmr.scan_items[i]))) {
            count++;
        }
    }
    if (count > 0) {
        wifi_mgmr_scan_ap_all(pstResults, &num, cb_scan_item_parse);
    }

    if (*size < count) {
        free(pstResults);
        if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return ERROR_WIFI_INVALID_ARGS;
    }

    int cpyErr;
    for (unsigned int i = 0; i < count; i++) {
        cpyErr = memcpy_s(result[i].ssid, BL_WIFI_MAX_SSID_LEN, pstResults[i].ssid, BL_WIFI_MAX_SSID_LEN);
        if (cpyErr != EOK) {
            free(pstResults);
            printf("[wifi_service]:GetScanInfoList memcpy failed, err = %d\r\n", cpyErr);
            if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
                return ERROR_WIFI_UNKNOWN;
            }
            return ERROR_WIFI_UNKNOWN;
        }

        cpyErr = memcpy_s(result[i].bssid, WIFI_MAC_LEN, pstResults[i].bssid, WIFI_MAC_LEN);
        if (cpyErr != EOK) {
            free(pstResults);
            printf("[wifi_service]:GetScanInfoList memcpy failed, err = %d\r\n", cpyErr);
            if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
                return ERROR_WIFI_UNKNOWN;
            }
            return ERROR_WIFI_UNKNOWN;
        }

        result[i].securityType = BLSecToHoSec(pstResults[i].auth);
        result[i].rssi = pstResults[i].rssi;
        result[i].frequency = ChannelToFrequency(pstResults[i].channel);
    }

    free(pstResults);
    *size = count;
    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    return WIFI_SUCCESS;
}

WifiErrorCode AddDeviceConfig(const WifiDeviceConfig* config, int* result)
{
    int fd = -1;
    char temp[20];
    char tempbuffer[256];
    const char space[] = "\r\n";

    if (config == NULL || result == NULL) {
        return ERROR_WIFI_INVALID_ARGS;
    }

    int netId = WIFI_CONFIG_INVALID;
    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    for (int i = 0; i < WIFI_MAX_CONFIG_SIZE; i++) {
        if (g_wifiConfigs[i].netId != i) {
            netId = i;
            break;
        }
    }

    if (netId == WIFI_CONFIG_INVALID) {
        printf("[wifi_service]:AddDeviceConfig wifi config is full, delete one first\r\n");
        if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return ERROR_WIFI_BUSY;
    }

    int cpyErr = memcpy_s(&g_wifiConfigs[netId], sizeof(WifiDeviceConfig), config, sizeof(WifiDeviceConfig));
    if (cpyErr != EOK) {
        if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        printf("[wifi_service]:AddDeviceConfig memcpy failed, err = %d\r\n", cpyErr);
        return ERROR_WIFI_UNKNOWN;
    }

    g_wifiConfigs[netId].netId = netId;
    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    // write config to flash
    HalFileDelete(CONFIG_FILE_NAME);
    fd = HalFileOpen(CONFIG_FILE_NAME, O_RDWR_FS | O_CREAT_FS, "wb+");
    if (fd < 0) {
        printf("allocate space for config file Failed\r\n");
    } else {
        printf("allocate space for config file OK\r\n");

        memset(temp, 0x00, sizeof(temp));
        memset(tempbuffer, 0x00, sizeof(tempbuffer));
        
        // ssid
        strcpy(tempbuffer, g_wifiConfigs[netId].ssid);
        strcat(tempbuffer, space);

        // bssid
        if (0 == strcmp(g_wifiConfigs[netId].bssid, "")) {
            strcat(tempbuffer, "0");
        } else {
            strcat(tempbuffer, g_wifiConfigs[netId].bssid);
        }
        strcat(tempbuffer, space);

        // preSharedKey
        if (0 == strcmp(g_wifiConfigs[netId].preSharedKey, "")) {
            strcat(tempbuffer, "0");
        } else {
            strcat(tempbuffer, g_wifiConfigs[netId].preSharedKey);
        }
        strcat(tempbuffer, space);

        // securityType
        strcpy(temp, "");
        snprintf(temp, 20, "%d", g_wifiConfigs[netId].securityType);
        strcat(tempbuffer, temp);
        strcat(tempbuffer, space);
        
        // netId
        strcpy(temp, "");
        snprintf(temp, 20, "%d", g_wifiConfigs[netId].netId);
        strcat(tempbuffer, temp);
        strcat(tempbuffer, space);

        // freq
        strcpy(temp, "");
        snprintf(temp, 20, "%d", g_wifiConfigs[netId].freq);
        strcat(tempbuffer, temp);
        strcat(tempbuffer, space);

        // wapiPskType
        strcpy(temp, "");
        snprintf(temp, 20, "%d", g_wifiConfigs[netId].wapiPskType);
        strcat(tempbuffer, temp);
        strcat(tempbuffer, space);

        // ipType
        strcpy(temp, "");
        snprintf(temp, 20, "%d", g_wifiConfigs[netId].ipType);
        strcat(tempbuffer, temp);
        strcat(tempbuffer, space);

        // staticIp.ipAddress
        strcpy(temp, "");
        snprintf(temp, 20, "%d", g_wifiConfigs[netId].staticIp.ipAddress);
        strcat(tempbuffer, temp);
        strcat(tempbuffer, space);

        // staticIp.gateway
        strcpy(temp, "");
        snprintf(temp, 20, "%d", g_wifiConfigs[netId].staticIp.gateway);
        strcat(tempbuffer, temp);
        strcat(tempbuffer, space);

        // staticIp.dnsServers[0]
        strcpy(temp, "");
        snprintf(temp, 20, "%d", g_wifiConfigs[netId].staticIp.dnsServers[0]);
        strcat(tempbuffer, temp);
        strcat(tempbuffer, space);

        // staticIp.dnsServers[1]
        strcpy(temp, "");
        snprintf(temp, 20, "%d", g_wifiConfigs[netId].staticIp.dnsServers[1]);
        strcat(tempbuffer, temp);

        HalFileWrite(fd, tempbuffer, 255);
        HalFileClose(fd);
    }   

    *result = netId;
    return WIFI_SUCCESS;
}

WifiErrorCode GetDeviceConfigs(WifiDeviceConfig* result, unsigned int* size)
{
    int fd;
    char* dim;
    char tempbuffer[256] = "";
    const char space[] = "\r\n";
    fd = HalFileOpen(CONFIG_FILE_NAME, O_RDWR_FS, "wb+");
    if (fd < 0) {
        //printf("Open config file Failed\r\n");
        return ERROR_WIFI_NOT_AVAILABLE;
    } else {
        printf("Open config file OK\r\n");
    }   

    if (result == NULL || size == NULL) {
        return ERROR_WIFI_INVALID_ARGS;
    }

    unsigned int retIndex = 0;

    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    HalFileRead(fd, tempbuffer, 255);
    if (0 == strcmp(tempbuffer, "")) {
        HalFileClose(fd);
        printf("Read config file is NULL\r\n");
    } else {
        dim = strtok(tempbuffer, space);
        if(dim != NULL)
            strcpy(g_wifiConfigs[0].ssid, dim);

        dim = strtok(NULL, space);
        if(dim != NULL)
            strcpy(g_wifiConfigs[0].bssid, dim);

        dim = strtok(NULL, space);
        if(dim != NULL)
            strcpy(g_wifiConfigs[0].preSharedKey, dim);

        dim = strtok(NULL, space);
        if(dim != NULL)
            g_wifiConfigs[0].securityType = atoi(dim);

        dim = strtok(NULL, space);
        if(dim != NULL)
            g_wifiConfigs[0].netId = atoi(dim);

        dim = strtok(NULL, space);
        if(dim != NULL)
            g_wifiConfigs[0].freq = atoi(dim);

        dim = strtok(NULL, space);
        if(dim != NULL)
            g_wifiConfigs[0].wapiPskType = atoi(dim);

        dim = strtok(NULL, space);
        if(dim != NULL)
            g_wifiConfigs[0].ipType = atoi(dim);

        dim = strtok(NULL, space);
        if(dim != NULL)
            g_wifiConfigs[0].staticIp.ipAddress = atoi(dim);
        
        dim = strtok(NULL, space);
        if(dim != NULL)
            g_wifiConfigs[0].staticIp.gateway = atoi(dim);
        
        dim = strtok(NULL, space);
        if(dim != NULL)
            g_wifiConfigs[0].staticIp.dnsServers[0] = atoi(dim);

        dim = strtok(NULL, space);
        if(dim != NULL)
            g_wifiConfigs[0].staticIp.dnsServers[1] = atoi(dim);

        HalFileClose(fd);
    }

    for (int i = 0; i < WIFI_MAX_CONFIG_SIZE; i++) {
        if (g_wifiConfigs[i].netId != i) {
            continue;
        }

        int cpyErr = memcpy_s(&result[retIndex], sizeof(WifiDeviceConfig), &g_wifiConfigs[i], sizeof(WifiDeviceConfig));
        if (cpyErr != EOK) {
            if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
                return ERROR_WIFI_UNKNOWN;
            }
            printf("[wifi_service]:GetDeviceConfig memcpy failed, err = %d\r\n", cpyErr);
            return ERROR_WIFI_UNKNOWN;
        }

        retIndex++;    
    }

    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    if (retIndex == 0) {
        return ERROR_WIFI_NOT_AVAILABLE;
    }

    *size = retIndex+1;
    return WIFI_SUCCESS;
}

static WifiErrorCode StaConnect(unsigned int chan, bl_wifi_assoc_request *assocReq, int pskType)
{
    int hiRet = 0;
    int lastState = g_connectState;

    (void)chan;
    (void)pskType;
    g_connectState = WIFI_STATE_NOT_AVALIABLE;

    hiRet = wifi_mgmr_sta_connect(g_wifiInterface, assocReq->ssid, assocReq->key, NULL, NULL, 0, 0);
 
    if (memset_s(assocReq, sizeof(bl_wifi_assoc_request), 0, sizeof(bl_wifi_assoc_request)) != EOK) {
        printf("[wifi_service]:StaConnect memset failed\r\n");
    }
    if (hiRet != BL_OK) {
        printf("[wifi_service]:wifi_mgmr_sta_connect failed\r\n");
        g_connectState = lastState;
        return ERROR_WIFI_UNKNOWN;
    }

    return WIFI_SUCCESS;
}

WifiErrorCode ConnectTo(int networkId)
{
    if (networkId >= WIFI_MAX_CONFIG_SIZE || networkId < 0) {
        return ERROR_WIFI_INVALID_ARGS;
    }

    if (g_wifiStaStatus != WIFI_STA_ACTIVE) {
        return ERROR_WIFI_NOT_STARTED;
    }

    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    if (g_wifiConfigs[networkId].netId != networkId) {
        if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return ERROR_WIFI_NOT_AVAILABLE;
    }

    bl_wifi_assoc_request assocReq = {0};
    assocReq.auth = HoSecToBLSec(g_wifiConfigs[networkId].securityType);

    int cpyErr = memcpy_s(assocReq.ssid, sizeof(assocReq.ssid),
        g_wifiConfigs[networkId].ssid, sizeof(g_wifiConfigs[networkId].ssid));
    cpyErr += memcpy_s(assocReq.key, sizeof(assocReq.key),
        g_wifiConfigs[networkId].preSharedKey, sizeof(g_wifiConfigs[networkId].preSharedKey));
    cpyErr += memcpy_s(assocReq.bssid, sizeof(assocReq.bssid),
        g_wifiConfigs[networkId].bssid, sizeof(g_wifiConfigs[networkId].bssid));
    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    if (cpyErr != EOK) {
        printf("[wifi_service]:ConnectTo memcpy failed, err = %d\r\n", cpyErr);
        return ERROR_WIFI_UNKNOWN;
    }

    unsigned int chan = FrequencyToChannel(g_wifiConfigs[networkId].freq);
    if (LockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    if (StaConnect(chan, &assocReq, g_wifiConfigs[networkId].wapiPskType) != WIFI_SUCCESS) {
        if (UnlockWifiEventLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return ERROR_WIFI_UNKNOWN;
    }
    if (UnlockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    return WIFI_SUCCESS;
}

WifiErrorCode Disconnect(void)
{
    if (g_wifiStaStatus != WIFI_STA_ACTIVE) {
        return ERROR_WIFI_NOT_STARTED;
    }
    int hiRet = wifi_mgmr_sta_disconnect();
    if (hiRet != BL_OK) {
        return ERROR_WIFI_UNKNOWN;
    }

    osDelay(200);
    wifi_mgmr_sta_disable(NULL);
    return WIFI_SUCCESS;
}

WifiErrorCode RemoveDevice(int networkId)
{
    if (networkId < 0) {
        printf("networkId < 0 Error!\r\n");
        return ERROR_WIFI_INVALID_ARGS;
    }
    HalFileDelete(CONFIG_FILE_NAME);
    if (LockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    if (memset_s(&g_wifiConfigs[networkId], sizeof(WifiDeviceConfig),
        0, sizeof(WifiDeviceConfig)) != EOK) {
        printf("[wifi_service]:removeDevice memset failed\r\n");
    }
    g_wifiConfigs[networkId].netId = WIFI_CONFIG_INVALID;
    if (UnlockWifiGlobalLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    return WIFI_SUCCESS;
}

WifiErrorCode GetLinkedInfo(WifiLinkedInfo* result)
{
    uint32_t ip = 0;
    uint32_t gw = 0;
    uint32_t mask = 0;
    wifi_mgmr_sta_connect_ind_stat_info_t info = {0};

    if (result == NULL) {
        return ERROR_WIFI_INVALID_ARGS;
    }
    
    wifi_mgmr_sta_connect_ind_stat_get(&info);

    int cpyErr = memcpy_s(result->ssid, WIFI_MAX_SSID_LEN - 1, info.ssid, BL_WIFI_MAX_SSID_LEN);
    if (cpyErr != EOK) {
        printf("[wifi_service]:GetLinkedInfo memcpy failed, err = %d\r\n", cpyErr);
        return ERROR_WIFI_UNKNOWN;
    }

    cpyErr = memcpy_s(result->bssid, WIFI_MAC_LEN, info.bssid, BL_WIFI_MAC_LEN);
    if (cpyErr != EOK) {
        printf("[wifi_service]:GetLinkedInfo memcpy failed, err = %d\r\n", cpyErr);
        return ERROR_WIFI_UNKNOWN;
    }

    wifi_mgmr_sta_ip_get(&ip, &gw, &mask);
#if 0 // clear the log
    printf("IP GOT IP:%u.%u.%u.%u\r\n",
        (unsigned int)((ip & 0x000000FF) >> 0),
        (unsigned int)((ip & 0x0000FF00) >> 8),
        (unsigned int)((ip & 0x00FF0000) >> 16),
        (unsigned int)((ip & 0xFF000000) >> 24));
#endif
    result->ipAddress = (int)ip;
    if (ip != 0) {
        result->connState = WIFI_CONNECTED;
        wifi_mgmr_rssi_get(&result->rssi);
    } else {
        result->connState = WIFI_DISCONNECTED;
    }

    return WIFI_SUCCESS;
}


WifiErrorCode RegisterWifiEvent(WifiEvent* event)
{
    if (event == NULL) {
        return ERROR_WIFI_INVALID_ARGS;
    }

    int emptySlot = WIFI_CONFIG_INVALID;

    if (LockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
        if (g_wifiEvents[i] == event) {
            if (UnlockWifiEventLock() != WIFI_SUCCESS) {
                return ERROR_WIFI_UNKNOWN;
            }
            return ERROR_WIFI_INVALID_ARGS;
        }

        if (g_wifiEvents[i] != NULL) {
            continue;
        }

        emptySlot = i;
        break;
    }

    if (emptySlot == WIFI_CONFIG_INVALID) {
        if (UnlockWifiEventLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return ERROR_WIFI_BUSY;
    }

    g_wifiEvents[emptySlot] = event;
    if (UnlockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    return WIFI_SUCCESS;
}

WifiErrorCode UnRegisterWifiEvent(const WifiEvent* event)
{
    if (event == NULL) {
        return ERROR_WIFI_INVALID_ARGS;
    }

    if (LockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }

    for (int i = 0; i < WIFI_MAX_EVENT_SIZE; i++) {
        if (g_wifiEvents[i] != event) {
            continue;
        }

        g_wifiEvents[i] = 0;

        if (UnlockWifiEventLock() != WIFI_SUCCESS) {
            return ERROR_WIFI_UNKNOWN;
        }
        return WIFI_SUCCESS;
    }

    if (UnlockWifiEventLock() != WIFI_SUCCESS) {
        return ERROR_WIFI_UNKNOWN;
    }
    return ERROR_WIFI_UNKNOWN;
}

WifiErrorCode GetDeviceMacAddress(unsigned char* result)
{
    if (result == NULL) {
        return ERROR_WIFI_INVALID_ARGS;
    }

    int hiRet = wifi_mgmr_sta_mac_get((uint8_t *)result);
    if (hiRet != BL_OK) {
        return ERROR_WIFI_UNKNOWN;
    }
    return WIFI_SUCCESS;
}
